﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Workflows.Components.TextMining.Clustering
{
    /// <summary>
    /// 
    /// </summary>
    public class KNearestNeighborCluster:IDocumentCluster
    {
        #region fields
        private Dictionary<int, Dictionary<int, DocTermFreq>> _DocTerms;
        private Dictionary<string, List<int>> _TermStemmings2;
        private Dictionary<int, string> _TermStemmings1;
        private int _NGramLen = 0;

        private IDistanceCalculator _DistanceCalculator;
        private IPurityCalculator _PurityCalculator;
        private Dictionary<int, double> _TermWeights;
        private Dictionary<int, ClusterNode> _ClusterResult;

        private double _ReassociationDistanceRatio = 1.50;
        private bool _CanOverlap;
        private int _K = 8;
        private const int _MaxIterationCount = 100;
        private double _TermFreqThreshold;
        private double _TermCoverageThreshold;
        private double _ClusterDistanceThreshold;
        private Dictionary<int, double> _DocDistances;              // docid -> distance (average of distances to other docs within current cluster)
        #endregion


        #region IDocumentCluster Members

        public event ClusterStatusChanged OnClusterStatusChanged;

        public IDistanceCalculator DistanceCalculator
        {
            get { return _DistanceCalculator; }
            set { _DistanceCalculator = value; }
        }

        public IPurityCalculator PurityCalculator
        {
            get { return _PurityCalculator; }
            set { _PurityCalculator = value; }
        }

        public Dictionary<int, double> TermWeights
        {
            get { return _TermWeights; }
            set { _TermWeights = value; }
        }

        public bool CanOverlap
        {
            get { return _CanOverlap; }
            set { _CanOverlap = value; }
        }

        public double ReassociationRange
        {
            get { return _ReassociationDistanceRatio; }
            set { this._ReassociationDistanceRatio = value; }
        }

        public void SetThreshold(double termCoverageThreshold, double termFreqThreshold, double clusterDistanceThreshold)
        {
            this._TermCoverageThreshold = termCoverageThreshold;
            this._TermFreqThreshold = termFreqThreshold;
            this._ClusterDistanceThreshold = clusterDistanceThreshold;
        }

        public Dictionary<int, ClusterNode> ClusterDocuments(
            Dictionary<int, Dictionary<int, DocTermFreq>> docTerms,
            bool useNgram, int ngramLen)
        {
            if (useNgram)
                this._NGramLen = ngramLen;
            return this.ClusterDocuments(docTerms, null, null);
        }

        public Dictionary<int, ClusterNode> ClusterDocuments(
            Dictionary<int, Dictionary<int, DocTermFreq>> docTerms,
            Dictionary<int,string> termStemmings1,
            Dictionary<string,List<int>> termStemmings2)
        {
            this._DocTerms = docTerms;
            this._TermStemmings1 = termStemmings1;
            this._TermStemmings2 = termStemmings2;

            this._ClusterResult = new Dictionary<int, ClusterNode>();

            return this._ClusterResult;
        }
        #endregion
    }
}
